use fltk::{
    app::{self, App},
    enums::{CallbackTrigger, Font},
    prelude::*,
};
use fltk_theme::WidgetTheme;
use myuifile::UserInterface;
use rand::Rng;
mod myuifile;

#[derive(Debug, Clone, Copy)]
enum Message {
    Generate,
    Copy,
}

struct MyApp {
    app: App,
    ui: UserInterface,
    receiver: app::Receiver<Message>,
}

impl MyApp {
    fn new() -> Self {
        let app = App::default();
        let widget_theme = WidgetTheme::new(fltk_theme::ThemeType::Aero);
        widget_theme.apply();
        let (sender, receiver) = app::channel::<Message>();
        let mut ui = myuifile::UserInterface::make_window();

        ui.input_length.emit(sender.clone(), Message::Generate);
        ui.input_length.set_trigger(CallbackTrigger::Changed);
        ui.input_num.emit(sender.clone(), Message::Generate);
        ui.input_num.set_trigger(CallbackTrigger::Changed);
        ui.check_lowercase.emit(sender.clone(), Message::Generate);
        ui.check_uppercase.emit(sender.clone(), Message::Generate);
        ui.check_number.emit(sender.clone(), Message::Generate);
        ui.check_special_character
            .emit(sender.clone(), Message::Generate);
        ui.button_generate.emit(sender.clone(), Message::Generate);
        ui.button_copy.emit(sender.clone(), Message::Copy);

        ui.input_result.set_text_font(Font::Helvetica);

        ui.input_num.set_value("4");
        ui.input_length.set_value("100");

        Self { app, ui, receiver }
    }

    fn launch(&mut self) {
        while self.app.wait() {
            use Message::*;
            if let Some(msg) = self.receiver.recv() {
                match msg {
                    Generate => {
                        let num = self.ui.input_num.value().parse::<u32>();
                        let length = self.ui.input_length.value().parse::<u32>();
                        if num.is_ok() && length.is_ok() {
                            let mut random_stirngs = String::new();
                            for _ in 0..num.unwrap() {
                                let random_string = generate_random_string(
                                    length.clone().unwrap(),
                                    self.ui.check_lowercase.value(),
                                    self.ui.check_uppercase.value(),
                                    self.ui.check_number.value(),
                                    self.ui.check_special_character.value(),
                                );
                                random_stirngs.push_str(&(random_string + "\n"));
                            }
                            self.ui.input_result.set_value(&random_stirngs);
                        } else {
                            continue;
                        }
                    }
                    Copy => {
                        fltk::app::copy(&self.ui.input_result.value());
                    }
                }
            }
        }
    }
}

fn build_character_set(
    include_lowercase: bool,
    include_uppercase: bool,
    include_numerals: bool,
    include_special_chars: bool,
) -> Vec<u8> {
    const LOWERCASE_ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
    const UPPERCASE_ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const NUMERALS: &[u8] = b"0123456789";
    const SPECIAL_CHARACTERS: &[u8] = b"!@#$%^&*()_+{}[]|;:,.<>?/~`";

    let mut charset = Vec::new();

    if include_lowercase {
        charset.extend_from_slice(LOWERCASE_ALPHABET);
    }
    if include_uppercase {
        charset.extend_from_slice(UPPERCASE_ALPHABET);
    }
    if include_numerals {
        charset.extend_from_slice(NUMERALS);
    }
    if include_special_chars {
        charset.extend_from_slice(SPECIAL_CHARACTERS);
    }

    charset
}
fn generate_random_string(
    length: u32,
    include_lowercase: bool,
    include_uppercase: bool,
    include_number: bool,
    include_special_character: bool,
) -> String {
    // let charset
    let charset = build_character_set(
        include_lowercase,
        include_uppercase,
        include_number,
        include_special_character,
    );
    if charset.is_empty() {
        return String::new();
    }
    let mut rng = rand::thread_rng();
    let mut result_chars: Vec<char> = Vec::with_capacity(length as usize);

    for _ in 0..length {
        let random_index = rng.gen_range(0..charset.len());
        let random_char = charset[random_index] as char;
        result_chars.push(random_char);
    }

    String::from_iter(result_chars)
}

fn main() {
    let mut fltk_template = MyApp::new();
    fltk_template.launch();
}
